package com.the_last.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.the_last.mapper.ReservationTimeSlotMapper;
import com.the_last.mapper.TimeSlotMapper;
import com.the_last.mapper.VenueMapper;
import com.the_last.mapper.convert.VenueConvert;
import com.the_last.pojo.dto.VenueDto;
import com.the_last.pojo.po.SportType;
import com.the_last.pojo.po.TimeSlot;
import com.the_last.pojo.po.Venue;
import com.the_last.pojo.vo.PageVO;
import com.the_last.pojo.vo.TimeSlotVO;
import com.the_last.pojo.vo.VenueTreeVO;
import com.the_last.pojo.vo.VenueVO;
import com.the_last.service.ReservationService;
import com.the_last.service.SpecialTimeService;
import com.the_last.service.SportTypeService;
import com.the_last.service.VenueService;
import com.the_last.utils.DateUtil;
import com.the_last.utils.RedisUtil;
import com.the_last.utils.Result;
import com.the_last.utils.TimeUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author zhanghaifeng
 * @description 针对表【Venue】的数据库操作Service实现
 * @createDate 2025-06-03 17:44:24
 */
@Service
@RequiredArgsConstructor
@Slf4j
public class VenueServiceImpl extends ServiceImpl<VenueMapper, Venue>
        implements VenueService {
    
    
    private final SpecialTimeService specialTimeService;
    private final TimeSlotMapper timeSlotMapper;
    private final ReservationService reservationService;
    private final ReservationTimeSlotMapper reservationTimeSlotMapper;
    private final RedissonClient redissonClient;
    private final RedisUtil redisUtil;
    private final SportTypeService sportTypeService;
    
    /**
     * 删除场馆树形结构缓存
     */
    private void clearVenueTreeCache() {
        redisUtil.delete("venue:tree");
    }
    
    
    @Override
    public Result<PageVO<VenueVO>> getVenuesBySportTypeId(Integer sportTypeId, Integer status, Integer pageNum, Integer pageSize) {
        // 创建分页对象
        Page<Venue> page = new Page<>(pageNum, pageSize);
        
        // 构建查询条件
        LambdaQueryWrapper<Venue> queryWrapper = new LambdaQueryWrapper<>();
        
        // 如果sportTypeId不为0，添加运动类型过滤
        if (sportTypeId != 0) {
            queryWrapper.eq(Venue::getSportTypeId, sportTypeId);
        }
        
        // 如果状态不为-1，添加状态过滤
        if (status != -1) {
            queryWrapper.eq(Venue::getStatus, status);
        }
        
        // 添加排序条件
        queryWrapper.orderByAsc(Venue::getId);
        
        // 执行分页查询
        Page<Venue> result = this.page(page, queryWrapper);
        
        // 转换为VO对象
        List<VenueVO> voList = result.getRecords().stream()
                .map(VenueConvert.INSTANCE::toVO)
                .collect(Collectors.toList());
        
        // 构建分页返回对象
        PageVO<VenueVO> pageVO = new PageVO<>();
        pageVO.setRecords(voList);
        pageVO.setTotal(result.getTotal());
        
        return Result.success(pageVO);
    }
    
    @Override
    public Result<List<TimeSlotVO>> getTimeslotsByVenueId(Integer venueId, String date) {
        List<TimeSlotVO> result = new ArrayList<>();
        
        // 获取时间段列表
        List<TimeSlot> list = timeSlotMapper.selectByVenueId(venueId);
        for (TimeSlot t : list) {
            TimeSlotVO vo = new TimeSlotVO();
            vo.setId(t.getId());
            vo.setStartTime(t.getStartTime() == null ? null : DateUtil.TIME_FORMAT.format(t.getStartTime()));
            vo.setEndTime(t.getEndTime() == null ? null : DateUtil.TIME_FORMAT.format(t.getEndTime()));
            vo.setIsOccupied(false); // 默认未占用
            result.add(vo);
        }
        
        try {
            List<Integer> occupiedTimeSlots = reservationTimeSlotMapper.getOccupiedTimeSlots(
                    venueId,
                    date
            );
            
            if (!CollectionUtils.isEmpty(occupiedTimeSlots)) {
                result.stream().filter(vo -> occupiedTimeSlots.contains(vo.getId())).forEach(vo -> vo.setIsOccupied(true));
            }
            
        } catch (Exception e) {
            return Result.fail("日期格式错误，请使用yyyy-MM-dd格式");
        }
        
        return Result.success(result);
    }
    
    @Override
    public Result<String> updateVenue(VenueDto venueDto) {
        if (venueDto == null) {
            return Result.fail("更新数据不能为空");
        }
        
        try {
            // 根据name查询场地是否存在
            LambdaQueryWrapper<Venue> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Venue::getId, venueDto.getId());
            Venue existingVenue = getOne(queryWrapper);
            
            if (existingVenue == null) {
                return Result.fail("场地不存在");
            }
            
            boolean nameChanged = !existingVenue.getName().equals(venueDto.getName());
            
            // 更新场地信息
            existingVenue.setName(venueDto.getName());
            existingVenue.setSportTypeId(venueDto.getSportTypeId());
            existingVenue.setStatus(venueDto.getStatus());
            existingVenue.setLocation(venueDto.getLocation());
            existingVenue.setImageUrl(venueDto.getImageUrl());
            existingVenue.setDescription(venueDto.getDescription());
            
            // 转换并设置开放时间和关闭时间
            if (venueDto.getOpenTime() != null) {
                existingVenue.setOpenTime(TimeUtil.timeFormat.parse(venueDto.getOpenTime()));
            }
            if (venueDto.getCloseTime() != null) {
                existingVenue.setCloseTime(TimeUtil.timeFormat.parse(venueDto.getCloseTime()));
            }
            
            // 更新到数据库
            boolean success = updateById(existingVenue);
            if (success) {
                if (nameChanged) {
                    // 清除场馆树形结构缓存
                    clearVenueTreeCache();
                }
                return Result.success("场地更新成功");
            } else {
                return Result.fail("场地更新失败");
            }
        } catch (Exception e) {
            log.error("更新场地信息失败", e);
            return Result.fail("更新场地信息失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<Void> addVenue(VenueDto venueDto) {
        if (venueDto == null) {
            return Result.fail("新增数据不能为空");
        }
        
        try {
            // 创建新的场地对象
            Venue venue = new Venue();
            venue.setName(venueDto.getName());
            venue.setSportTypeId(venueDto.getSportTypeId());
            venue.setStatus(venueDto.getStatus());
            venue.setLocation(venueDto.getLocation());
            venue.setImageUrl(venueDto.getImageUrl());
            venue.setDescription(venueDto.getDescription());
            
            // 转换并设置开放时间和关闭时间
            if (venueDto.getOpenTime() != null) {
                venue.setOpenTime(TimeUtil.timeFormat.parse(venueDto.getOpenTime()));
            }
            if (venueDto.getCloseTime() != null) {
                venue.setCloseTime(TimeUtil.timeFormat.parse(venueDto.getCloseTime()));
            }
            
            // 保存到数据库
            boolean success = save(venue);
            if (success) {
                // 清除场馆树形结构缓存
                clearVenueTreeCache();
                return Result.success();
            } else {
                return Result.fail("新增场地失败");
            }
        } catch (Exception e) {
            log.error("新增场地信息失败", e);
            return Result.fail("新增场地信息失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<Void> deleteVenue(Integer id) {
        if (id == null) {
            return Result.fail("场馆ID不能为空");
        }
        
        try {
            // 检查场馆是否存在
            Venue venue = getById(id);
            if (venue == null) {
                return Result.fail("场馆不存在");
            }
            
            // 检查是否有未完成的预约
            boolean hasActiveReservations = reservationService.hasActiveReservations(id);
            if (hasActiveReservations) {
                return Result.fail("该场馆还有未完成的预约，无法删除");
            }
            
            // 删除场馆
            boolean success = removeById(id);
            if (success) {
                // 清除场馆树形结构缓存
                clearVenueTreeCache();
                return Result.success();
            } else {
                return Result.fail("删除场馆失败");
            }
        } catch (Exception e) {
            log.error("删除场馆失败", e);
            return Result.fail("删除场馆失败：" + e.getMessage());
        }
    }
    
    @Override
    public Result<List<VenueTreeVO>> getVenueTree() {
        // 先从Redis中获取数据
        List<VenueTreeVO> venueTree = redisUtil.getList("venue:tree", VenueTreeVO.class);
        if (CollectionUtils.isEmpty(venueTree)) {
            // 如果Redis中没有数据，使用双检锁机制
            RLock lock = redissonClient.getLock("venue:tree:lock");
            try {
                lock.lock();
                // 再次从Redis中获取数据
                venueTree = redisUtil.getList("venue:tree", VenueTreeVO.class);
                if (CollectionUtils.isEmpty(venueTree)) {
                    // 如果还是没有数据，则从数据库中查询并构建树形结构
                    venueTree = new ArrayList<>();
                    
                    // 获取所有运动类型
                    List<SportType> sportTypes = sportTypeService.list();
                    
                    // 获取所有场馆
                    List<Venue> venues = list();
                    
                    // 按运动类型分组构建树形结构
                    for (SportType sportType : sportTypes) {
                        VenueTreeVO treeNode = new VenueTreeVO();
                        treeNode.setSportTypeId(sportType.getId());
                        treeNode.setSportTypeName(sportType.getName());
                        
                        // 过滤该运动类型的场馆
                        List<VenueTreeVO.VenueOption> venueOptions = venues.stream()
                                .filter(v -> v.getSportTypeId().equals(sportType.getId()))
                                .map(v -> {
                                    VenueTreeVO.VenueOption option = new VenueTreeVO.VenueOption();
                                    option.setId(v.getId());
                                    option.setName(v.getName());
                                    return option;
                                })
                                .collect(Collectors.toList());
                        
                        // 只有当该运动类型下有场馆时才添加到结果中
                        if (!venueOptions.isEmpty()) {
                            treeNode.setVenues(venueOptions);
                            venueTree.add(treeNode);
                        }
                    }
                    
                    // 将数据缓存到Redis中
                    redisUtil.setList("venue:tree", venueTree);
                }
            } finally {
                lock.unlock();
            }
        }
        return Result.success(venueTree);
    }
    
}

